package rdf;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.FileManager;

/**
 * Servlet implementation class SemanticServlet
 */
@WebServlet("/SemanticServlet/*")
public class SemanticServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	private static Model model;
	private static final String DEFAULT_URI = 
		"http://www.semanticweb.org/ontologies/2011/11/OntologyHockey_0627596.owl#";
	private static final String DEFAULT_ROOT_NAME = "Hockey";
	private static final String ROOT_NODE_URI = DEFAULT_URI + DEFAULT_ROOT_NAME;
	private static final String FILE_NAME_RDF = "OntologyHockey_0627596.rdf";

	/**
	 * Default constructor.
	 */
	public SemanticServlet() {
		// TODO Auto-generated constructor stub
	}
	

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		
		// create an empty model
		model = ModelFactory.createDefaultModel();

		// use the FileManager to find the input file
		InputStream in = FileManager.get().open(FILE_NAME_RDF);
		if (in == null) {
			throw new IllegalArgumentException("File: " + FILE_NAME_RDF
					+ " not found");
		}

		// read the RDF/XML file
		model.read(in, null);
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		
		String currentURI;
		String currentName;
		if(request.getRequestURI().endsWith("RDF_Browser/SemanticServlet/") || 
				request.getRequestURI().endsWith("RDF_Browser/SemanticServlet"))
		{
			currentName = DEFAULT_ROOT_NAME;
			currentURI = ROOT_NODE_URI;
			
		}
		else
		{
			String[] split = request.getRequestURI().split("/");
			int j=split.length-1;
			for(; j>=0; j--)
			{
				if(!split[j].equals(""))
					break;
			}
			currentName = split[j];
			currentURI = DEFAULT_URI + split[j];
		}
			
		// children 
		QueryExecution qe = QueryExecutionFactory.create(
				getTemplateQuery("rdfs:subClassOf",currentURI), model);
		ResultSet results = qe.execSelect();
		
		List<PropertyObject> objectProperties = getIndirectProperties(results, "rdfs", "hasSubClass");
		qe.close();
		
		// direct-access properties
		List<PropertyObject> directProperties = 
			getProperties(model.getResource(currentURI).listProperties());
		
		// individuals
		qe = QueryExecutionFactory.create(
				getTemplateQuery("rdf:type",currentURI), model);
		results = qe.execSelect();
		
		List<PropertyObject> individuals = getIndirectProperties(results,"", "hasMember");
		qe.close();
		
		
		// merge lists
		objectProperties.addAll(directProperties);
		objectProperties.addAll(individuals);
		
//		for(PropertyObject object :  subClasses)
//		{
//			System.out.println(object.getPrefixProperty() + ":" + object.getProperty() + " ; " 
//					+ object.getPrefixObject() + ":" + object.getObject());
//		}
		
		// html output
		Writer w = response.getWriter();

		w.write("<html><body>");
		w.write("<h1>" + currentName + "</h1>");
		
		w.write("<table border='1'>");
		w.write("<tr>");
		w.write("<th> Property </th>");
		w.write("<th> Object </th>");
		w.write("</tr>");
		
		for(PropertyObject propertyObject : objectProperties)
		{
			w.write("<tr><td>");
			if(!propertyObject.getPrefixProperty().isEmpty())
				w.write(propertyObject.getPrefixProperty()+":");
			w.write(propertyObject.getProperty());
			
			String slash = request.getRequestURI().endsWith("/") ? "" : "/RDF_Browser/SemanticServlet/";
			
			if(propertyObject.getExternURI()==null)
				w.write("</td><td><a href='"+ slash + propertyObject.getObject() + "'>");
			else
				w.write("</td><td><a href='"+ propertyObject.getExternURI() + "'>");
			
			if(propertyObject.getPrefixObject()!=null && 
					!propertyObject.getPrefixObject().isEmpty())
				w.write(propertyObject.getPrefixObject()+":");
			w.write(propertyObject.getObject()+"</a>");
			w.write("</td</tr>");
		}
		
		w.write("</table>");
		
		w.write("<br/> <a href='/RDF_Browser/SemanticQueryServlet/'>Query Engine</a>");
		w.write("</body></html>");
		
	}
	
	private static List<PropertyObject> getIndirectProperties(ResultSet results, String prefixProperty, 
			String property)
	{
		List<PropertyObject> propertyObjects = new ArrayList<PropertyObject>();
		
		while (results.hasNext()) {
			QuerySolution result = results.nextSolution();
			
			String prefixObject = model.getNsURIPrefix(result.getResource("child").getNameSpace());
			String object = result.getResource("child").getLocalName();
		
			propertyObjects.add(new PropertyObject(prefixProperty, property, prefixObject, 
					object));
		}
		
		return propertyObjects;
	}
	
	private static List<PropertyObject> getProperties(StmtIterator iter)
	{
		List<PropertyObject> propertyObjects = new ArrayList<PropertyObject>();
		
		while(iter.hasNext()) {
			Statement statement = iter.nextStatement();
			
			String prefixProperty = model.getNsURIPrefix(statement.getPredicate().getNameSpace());
			String property = statement.getPredicate().getLocalName();
			
			String prefixObject = model.getNsURIPrefix(statement.getObject().asResource().getNameSpace());
			String object = statement.getObject().asResource().getLocalName();
			
			if(object != null && !(prefixObject+object).equals("owlClass") && 
					!(prefixObject+object).equals("owlNamedIndividual"))
			{
				PropertyObject propertyObject = new PropertyObject(prefixProperty, property, prefixObject, object);
				
				if((prefixProperty+property).equals("owlsameAs"))
				{
					propertyObject.setExternURI(statement.getObject().asResource().getURI());
				}
					
				propertyObjects.add(propertyObject);
			}
				
		}
		
		return propertyObjects;
	}
	
	private static String getTemplateQuery(String predicate, String parameter)
	{
		return "PREFIX owl: <http://www.w3.org/2002/07/owl#> "
			+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
			+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
			+ "SELECT ?child WHERE { ?child " + predicate + " <" + parameter + "> }";
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

}
